package Drifter;

import MapPack.Cell;
import MapPack.Map;
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;

import java.util.HashMap;

public class DrifterMain extends ApplicationAdapter {
    // The batch process.
	private SpriteBatch batch;
    private BitmapFont font;

    // The game camera.
    private OrthographicCamera camera;

    // Textures.
    private int cellSize = 32;
    private HashMap<Map.CellEnum, Texture> cellEnumToTextureMap;
    private Texture validSelectionTexture;
    private Texture invalidSelectionTexture;

    // Miscellaneous.
    private int selectionRange = 3;
    private Cell selectedCell;

    // Smaller number is faster gameplay.
    private long gameSpeed = 50;
    private long lastUpdate = 0;
    private int lastKeypress;
    private static enum GameState {WAITING, PAUSED, ANIMATING, GAMEOVER}
    private GameState gameState = GameState.WAITING;

    // In charge of updating the game.
    private Driver driver;

    @Override
	public void create ( ) {
        this.batch = new SpriteBatch();
        this.font = new BitmapFont(Gdx.files.internal("consolas.fnt"));
        this.camera = new OrthographicCamera();
        this.camera.setToOrtho(false, 1440, 900);

        // Generate the driver.
        this.driver = new Driver();

        populateTextureMaps();
	}

    public void populateTextureMaps() {
        this.cellEnumToTextureMap = new HashMap<>();
        this.cellEnumToTextureMap.put(Map.CellEnum.EMPTY, new Texture("EmptyTile32.png"));
        this.cellEnumToTextureMap.put(Map.CellEnum.GRASS, new Texture("GrassTile32.png"));
        this.cellEnumToTextureMap.put(Map.CellEnum.MARTIANSOIL, new Texture("MartianSoil32.png"));
        this.cellEnumToTextureMap.put(Map.CellEnum.ICE, new Texture("IceTile32.png"));

        this.validSelectionTexture = new Texture("SelectionBorder32.png");
        this.invalidSelectionTexture = new Texture("InvalidSelectionBorder32.png");
    }

	@Override
	public void render ( ) {
        switch (this.gameState) {
            case WAITING:
                draw();
                waitForInput();
                break;
            case PAUSED:
                displayMenu();
                break;
            case ANIMATING:
                draw();
                delayForAnimations();
                break;
            case GAMEOVER:
                Gdx.app.exit();
        }
	}

    public void waitForInput ( ) {
        // Check that the player is alive.
        if (!this.driver.getPlayer().isAlive()) {
            gameOver();
            return;
        }
        if (Gdx.input.isKeyPressed(Input.Keys.A)) {
            this.lastKeypress = Input.Keys.A;
        } else if (Gdx.input.isKeyPressed(Input.Keys.D)) {
            this.lastKeypress = Input.Keys.D;
        } else if (Gdx.input. isKeyPressed(Input.Keys.S)) {
            this.lastKeypress = Input.Keys.S;
        } else if (Gdx.input.isKeyPressed(Input.Keys.W)) {
            this.lastKeypress = Input.Keys.W;
        } else if (Gdx.input.isKeyPressed(Input.Keys.T)) {
            this.lastKeypress = Input.Keys.T;
        } else if (Gdx.input.isKeyPressed(Input.Keys.R)
                && this.selectedCell != null
                && this.selectedCell.isWithinDistance(this.driver.getPlayer(), this.selectionRange)) {
            this.lastKeypress = Input.Keys.R;
        } else if (Gdx.input.isButtonPressed(Input.Buttons.LEFT)
                && this.selectedCell != null
                && this.selectedCell.isWithinDistance(this.driver.getPlayer(), this.selectionRange)) {
            this.lastKeypress = Input.Buttons.LEFT;
        } else if (Gdx.input.isButtonPressed(Input.Buttons.RIGHT)
                && this.selectedCell != null
                && this.selectedCell.isWithinDistance(this.driver.getPlayer(), this.selectionRange)) {
            this.lastKeypress = Input.Buttons.RIGHT;
        } else if (Gdx.input.isKeyPressed(Input.Keys.ESCAPE)) {
            pause();
            return;
        }

        if (this.lastKeypress > -2) {
            this.driver.drive(this.lastKeypress, this.selectedCell);
            animate();
        }

        this.lastKeypress = -2;
    }

    public void displayMenu ( ) {
        if (true) {
            resume();
        }
    }

    public void delayForAnimations ( ) {
        if (this.lastUpdate > 0) {
            if (System.currentTimeMillis() > this.lastUpdate + this.gameSpeed) {
                resume();
                this.lastUpdate = 0;
            }
        } else {
            this.lastUpdate = System.currentTimeMillis();
        }
    }

    public void draw ( ) {
        // Clear the screen.
        Gdx.gl.glClearColor(0.25f, 0.65f, 0.95f, 0.1f);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

        // Camera follows the player.
        this.camera.position.set(this.driver.getPlayer().getX() * this.cellSize,
                                 this.driver.getPlayer().getY() * this.cellSize,
                                 0);
        this.camera.update();

        // Paint the world!
        this.batch.setProjectionMatrix(this.camera.combined);
        this.batch.begin();
        int playerX = this.driver.getPlayer().getX();
        int playerY = this.driver.getPlayer().getY();
        int horizontalCellRadius = (int) Math.ceil(this.camera.viewportWidth / 2.0 / this.cellSize);
        int verticalCellRadius = (int) Math.ceil(this.camera.viewportHeight / 2.0 / this.cellSize);

        // Paint the map cells.
        for (int x = playerX - horizontalCellRadius; x < playerX + horizontalCellRadius; x++) {
            for (int y = playerY - verticalCellRadius; y < playerY + verticalCellRadius; y++) {
                if (this.driver.getMap().getMapCell(x, y) == null) {
                    continue;
                }
                int pixelX = x * this.cellSize;
                int pixelY = y * this.cellSize;
                Map.CellEnum cellType = this.driver.getMap().getMapCell(x, y).getCellType();
                if (this.cellEnumToTextureMap.containsKey(cellType)) {
                    this.batch.draw(this.cellEnumToTextureMap.get(cellType), pixelX, pixelY);
                }
            }
        }

        // Paint the entities.
        this.driver.getEntities().stream().filter(e ->
                e.getX() < playerX + horizontalCellRadius &&
                e.getY() < playerY + verticalCellRadius)
                .forEach(f -> this.batch.draw(f.getTexture(),
                        f.getX() * this.cellSize,
                        f.getY() * this.cellSize));

        // Paint the player's selected cell.
        this.selectedCell = this.driver.getMap().getMapCell(
                playerX + (int) Math.floor((Gdx.input.getX()
                        - this.camera.viewportWidth / 2) / this.cellSize),
                playerY + (int) Math.floor((this.camera.viewportHeight
                        - Gdx.input.getY() - this.camera.viewportHeight / 2) / this.cellSize));
        Texture selectionTexture = invalidSelectionTexture;
        if (this.selectedCell != null) {
            if (this.selectedCell.isWithinDistance(this.driver.getPlayer(), this.selectionRange)) {
                selectionTexture = validSelectionTexture;
            }
            this.batch.draw(selectionTexture,
                    this.selectedCell.getX() * this.cellSize,
                    this.selectedCell.getY() * this.cellSize);
        }

        // Display HUD text.
        this.batch.setProjectionMatrix(this.camera.projection);

        //Bar bar = new Bar();
        //bar.setPosition(-680f, -270f);
        //bar.draw(this.batch, this.driver.getPlayer().getSuit().getOxygenPercent());

        font.setColor(0.0f, 0.0f, 0.0f, 1f);
        font.setScale(2.0f);

        font.draw(this.batch,
                "T: " + this.driver.getElapsedTime(),
                -690f,
                -310f);
        font.draw(this.batch,
                "E: " + Math.round(100.0 * this.driver.getPlayer().getSuit().getEnergyPercent()),
                -690f,
                -345f);
        font.draw(this.batch,
                "O\u2082: " + Math.round(100.0 * this.driver.getPlayer().getSuit().getOxygenPercent()),
                -690f,
                -380f);
        font.draw(this.batch,
                "X: " + this.driver.getPlayer().getX() +
                        "  Y: " + this.driver.getPlayer().getY() +
                        "  Z: " + this.driver.getPlayer().getPosition().getElevation(),
                -690f,
                -415f);
        if (!this.driver.getPlayer().isAlive()) {
            font.setColor(1.0f, 0.0f, 0.0f, 1f);
            font.draw(this.batch,
                    "I'm dead now", 0, 0);
        }

        this.batch.end();
    }

    @Override
    public void pause ( ) {
        this.gameState = GameState.PAUSED;
    }

    @Override
    public void resume ( ) {
        this.gameState = GameState.WAITING;
    }

    public void animate ( ) {
        this.gameState = GameState.ANIMATING;
    }

    public void gameOver ( ) {
        //this.gameState = GameState.GAMEOVER;
    }

}
